package com.czk.utlls;

import com.czk.pojo.*;
import com.thoughtworks.xstream.XStream;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.util.*;

/**
 * 验证服务来自微信的验证类
 *
 * @Author:ChenZhangKun
 * @Date: 2021/8/2 11:32
 */
@Slf4j
public class WeChatUtil {
    // 微信公众号开发者平台配置的token
    private static final String TOKEN = "czk";

    /**
     * 验证是否微信微信服务器发送的消息
     *
     * @param timestamp
     * @param nonce
     * @param signature
     * @return
     */
    public static boolean check(String timestamp, String nonce, String signature) {
        String[] strs = {TOKEN, timestamp, nonce};
        // 排序
        Arrays.sort(strs);
        // 拼串
        String str = strs[0] + strs[1] + strs[2];
        // 加密
        String mysig = sha1(str);
        if (mysig != null) {
            log.info("加密后的字符串{}", mysig);
            // 对比
            return Objects.equals(mysig, signature);
        } else {
            log.error("加密失败");
            return false;
        }
    }

    private static String sha1(String str) {
        try {
            // 获取摘要加密算法
            MessageDigest md = MessageDigest.getInstance("sha1");
            // 加密
            byte[] digest = md.digest(str.getBytes());
            char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            StringBuilder builder = new StringBuilder();
            // 处理加密结果
            for (byte b : digest) {
                // 先处理高四位
                // 右移四位在于15进行与运算（00001111）去除符号位
                // 由于高四位最多为1111 为15,在十六进制的范围内
                char c = chars[(b >> 4) & 15];
                // 拼接到
                builder.append(c);
                builder.append(chars[b & 15]);
            }
            return builder.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解析xml
     *
     * @param request
     * @return
     */
    public static Map<String, String> parseRequest(HttpServletRequest request) {
        Map<String, String> map = new HashMap<>(16);
        // 解析xml
        SAXReader reader = new SAXReader();
        try {
            ServletInputStream inputStream = request.getInputStream();
            // 读取输入流
            Document document = reader.read(inputStream);
            // 获取根节点
            Element rootElement = document.getRootElement();
            // 拿到所有节点
            List<Element> elements = rootElement.elements();
            // 拿到键值
            for (Element element : elements) {
                map.put(element.getName(), element.getStringValue());
            }
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 用于处理所有的时间和消息的回复
     *
     * @param map
     * @return
     */
    public static String getResponse(Map<String, String> map) {
        // 拿到消息类型
        String msgType = map.get("MsgType");
        log.info("【消息的类型是】{}", msgType);
        BaseMessage baseMessage = null;
        switch (msgType) {
            case "text":
                baseMessage = MessageUtil.dealText(map);
                break;
            case "image":
               // baseMessage = MessageUtil.dealImage(map);
                baseMessage=MessageUtil.dealImageWithIdCard(map);
                break;
            case "voice":
                baseMessage = MessageUtil.dealVoice(map);
                break;
            case "shortvideo":
                baseMessage = MessageUtil.dealShortVideo(map);
                break;
            case "location":
                baseMessage = MessageUtil.dealLocation(map);
                break;
            case "video":
                baseMessage = MessageUtil.dealVideo(map);
                break;
            case "music":
                baseMessage = MessageUtil.dealMusic(map);
                break;
            case "article":
                baseMessage = MessageUtil.dealArticle(map);
                break;
            case "event":
                baseMessage=MessageUtil.dealEvent(map);
                break;
            case "link":
                baseMessage=MessageUtil.dealLink(map);
                break;
            default:
                log.error("不支持的消息类型");
                return "";
        }

        return beanToXml(baseMessage);
    }

    /**
     * 对象转为xml
     *
     * @param baseMessage
     * @return
     */
    private static String beanToXml(BaseMessage baseMessage) {
        XStream xstream = new XStream();
        xstream.processAnnotations(TextMessage.class);
        xstream.processAnnotations(ImageMessage.class);
        xstream.processAnnotations(MusicMessage.class);
        xstream.processAnnotations(NewsMessage.class);
        xstream.processAnnotations(VideoMessage.class);
        xstream.processAnnotations(VoiceMessage.class);
        String xml = xstream.toXML(baseMessage);
        return xml;
    }

    /**
     * 像指定地址发送post请求
     *
     * @param url
     * @param data
     * @return
     */
    public static String post(String url, String data) {
        try {
            URL uRL=new URL(url);
            URLConnection urlConnection = uRL.openConnection();
            // 发送数据
            urlConnection.setDoOutput(true);
            // 获取输出刘
            OutputStream outputStream = urlConnection.getOutputStream();
            // 写数据
            outputStream.write(data.getBytes());
            outputStream.close();
            // 拿到输入流
            InputStream inputStream = urlConnection.getInputStream();
            byte[] b = new byte[1024];
            int length = 0;
            StringBuilder builder = new StringBuilder();
            while ((length = inputStream.read(b)) != -1) {
                builder.append(new String(b, 0, length));
            }
            return builder.toString();
        }catch (Exception exception){
            exception.printStackTrace();
        }
        return null;
    }
}
